// $Id: output_cpp.hpp 2 2009-09-02 08:47:42Z joseph2002 $
/*
 * Copyright 2009 Joseph Wu
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 *
 * For more information, see http://xpcomplus.sourceforge.net
 */

#ifndef XPGEN_OUTPUT_CPP_HPP
#define XPGEN_OUTPUT_CPP_HPP

#include <iosfwd>
#include <string>
#include <vector>
#include <xpgen/output.hpp>

namespace xpgen {

struct interface_decl;
struct constant_decl;
struct method_decl;
struct param_decl;
struct type_decl;

void init();
void finish();

class output_cpp : public output
{
public:
    explicit output_cpp(output* prev = 0);
    virtual ~output_cpp();

    // index is type_decl::tag, empty means no map
    std::vector<std::string> native_types;
    bool upper_constant; // true will make constant name all uppercase
    bool upper_method; // true will make first letter of method name uppercase
    bool write_scriptable;

protected:
    virtual void do_reset();

protected:
    // Additional include flags
    enum include_flags
    {
        inc_array                   = 1 << 0,
        inc_array_fwd               = 1 << 1,
        inc_assert                  = 1 << 2,
        inc_exception               = 1 << 3,
        inc_interface               = 1 << 4,
        inc_ptr                     = 1 << 5,
        inc_ptr_array               = 1 << 6,
        inc_result_code             = 1 << 7,
        inc_string                  = 1 << 8,
        inc_ustring                 = 1 << 9,
        inc_xpcom                   = 1 << 10,
        inc_xpcom_impl              = 1 << 11,
        inc_proxy_array             = 1 << 12,
        inc_proxy_bool              = 1 << 13,
        inc_proxy_interface_proxy   = 1 << 14,
        inc_proxy_pstring           = 1 << 15,
        inc_proxy_ptr               = 1 << 16,
        inc_proxy_uuid_ptr          = 1 << 17,
        inc_impl_array              = 1 << 18,
        inc_impl_bool               = 1 << 19,
        inc_impl_exception          = 1 << 20,
        inc_impl_interface_impl     = 1 << 21,
        inc_impl_pstring            = 1 << 22,
        inc_impl_ptr                = 1 << 23,
        inc_impl_ptr_array          = 1 << 24,
        inc_impl_uuid_ptr           = 1 << 25
    };

    enum method_flags
    {
        method_proxied  = 1 << 0,
        method_impl     = 1 << 1
    };

    void print_file_header(std::ostream& os, const std::string& out_filename) const;
    void print_includes(std::ostream& os, unsigned inc_flags) const; // see include_flags

    void print_ns_begin(std::ostream& os, const std::string& ns_name);
    void print_ns_end(std::ostream& os);

    void print_interface_ns_begin(std::ostream& os, interface_decl* itf);
    void print_interface_ns_end(std::ostream& os, interface_decl* itf);
    void print_interface_forward(std::ostream& os, interface_decl* itf);

    void print_method_signature(std::ostream& os, method_decl* method, unsigned flags);

    std::string get_relative_ns_cpp(const std::string& ns) const;
    std::string get_relative_ns_cpp(const std::vector<std::string>& ns_list) const;
    std::string get_relative_interface_qname_cpp(interface_decl* itf) const;
    std::string get_relative_xpcom_qname_cpp(const std::string& name) const;

    std::string get_include_guard_name(
            interface_decl* itf, const std::string& suffix = std::string()) const;
    std::string get_include_guard_name(
            const std::string& basename, const std::string& suffix = std::string()) const;
    static std::string get_include_guard_basename(interface_decl* itf);

    static std::string get_name_cpp(const std::string& name);
    std::string get_constant_name_cpp(constant_decl* constant) const;
    std::string get_method_name_cpp(method_decl* method, bool proxied) const;
    std::string get_proxy_method_name_cpp(method_decl* method) const;

    std::string get_param_type_name(param_decl* param) const;
    std::string get_proxy_param_type_name(param_decl* param) const;

    std::string get_type_basename(type_decl* type) const;
    std::string get_proxy_type_basename(type_decl* type) const;
    std::string get_proxy_array_type_basename(type_decl* type) const;

    static std::string get_param_in_out_str(param_decl* param);
    static std::string get_param_size_length_str(param_decl* param);

    static bool is_param_pstring_with_size(param_decl* param);
    static bool is_proxy_param_primary(param_decl* param);
    static bool is_proxy_param_sub(param_decl* param);

    // XXX Special fix, for output array|pstring with input [size_is]
    // And for multiple primary params
    static bool is_param_out_isize2(param_decl* param);
    static void check_primary_param(param_decl* param);
    static void check_sub_param(param_decl* param);

private:
    static void init();
    static void finish();

    friend void xpgen::init();
    friend void xpgen::finish();
};

} // namespace xpgen

#endif // XPGEN_OUTPUT_CPP_HPP
